using Rhino.Mocks;
using MbUnit.Framework;

namespace NEnsure.UnitTests
{
	[TestFixture]
	public class BrokenRuleTests
	{
		private MockRepository _mocks;
		private IBusinessRule _rule;
		private IBusinessRule _rule2;
		private BrokenRule _one;
		private BrokenRule _two;
		private BrokenRule _three;
		private BrokenRuleList _list;
		
		[SetUp]
		public void Init()
		{
			_mocks = new MockRepository();

			_rule = _mocks.StrictMock<IBusinessRule>();
			_rule2 = _mocks.StrictMock<IBusinessRule>();
		}

		[Test]
		[ExpectedArgumentNullException]
		public void Should_Die_If_PropertyName_Is_Nothing()
		{
			BrokenRule brokenRule = new BrokenRule(null, null, _rule);
		}
		
		[Test]
		[ExpectedArgumentNullException]
		public void Should_Die_If_Rule_Is_Nothing()
		{
			BrokenRule brokenRule = new BrokenRule("P", null, null);
		}

		[Test]
		public void Should_Set_PropertyName_Correctly()
		{
			BrokenRule brokenRule = new BrokenRule("P", null, _rule);

			Assert.AreEqual("P", brokenRule.PropertyName);
		}

		[Test]
		public void Should_Set_PropertyValue_Correctly()
		{
			BrokenRule brokenRule = new BrokenRule("P", 9, _rule);

			Assert.AreEqual(9, (int) brokenRule.PropertyValue);
		}

		[Test]
		public void Should_Set_Rule_Correctly()
		{
			BrokenRule brokenRule = new BrokenRule("P", 9, _rule);

			Assert.AreEqual(_rule, brokenRule.Rule);
		}

		[Test]
		public void Should_Return_Correct_String_Representation()
		{
			string expected = "Property 'P' with value '9' broke rule 'Mock Rule.'";

			Expect.Call(_rule.RuleKey).Return("Mock Rule");
			Expect.Call(_rule.ErrorFormat).Return("a").Repeat.Twice();
			
			_mocks.ReplayAll();

			BrokenRule brokenRule = new BrokenRule("P", 9, _rule);

			Assert.AreEqual(expected, brokenRule.ToString());
		}

		[Test]
		public void Should_Build_Error_Message_Correctly()
		{
			string expected = "Mock Rule P = 10";

			Expect.Call(_rule.ErrorFormat).Return("Mock Rule {key} = {value}").Repeat.Twice();

			_mocks.ReplayAll();

			BrokenRule brokenRule = new BrokenRule("P", 10, _rule);

			Assert.AreEqual(expected, brokenRule.ErrorMessage);
		}

		[Test]
		public void Should_Get_All_Broken_Rules_For_Property()
		{
			Expect.Call(_rule.ErrorFormat).Return("1").Repeat.Times(4);
			Expect.Call(_rule2.ErrorFormat).Return("2").Repeat.Times(2);

			_mocks.ReplayAll();

			setupBrokenRuleList();

			BrokenRule[] forP = _list.GetBrokenRulesForProperty("P");

			Assert.AreEqual(2, forP.Length);
			Assert.AreEqual(_one, forP[0]);
			Assert.AreEqual(_two, forP[1]);
		}

		[Test]
		public void Should_Get_All_Broken_Rules_For_Business_RuleKey_Ignore_Case()
		{
			Expect.Call(_rule.ErrorFormat).Return("1").Repeat.Times(4);
			Expect.Call(_rule2.ErrorFormat).Return("2").Repeat.Times(2);
			Expect.Call(_rule.RuleKey).Return("1").Repeat.Times(2);
			Expect.Call(_rule2.RuleKey).Return("2");

			_mocks.ReplayAll();

			setupBrokenRuleList();

			BrokenRule[] forRule1 = _list.GetBrokenRulesForRule("1");

			Assert.AreEqual(2, forRule1.Length);
			Assert.AreEqual(_one, forRule1[0]);
			Assert.AreEqual(_three, forRule1[1]);

		}

		[Test]
		public void Should_Get_All_Broken_Rules_For_Business_Rule()
		{
			Expect.Call(_rule.ErrorFormat).Return("1").Repeat.Times(4);
			Expect.Call(_rule2.ErrorFormat).Return("2").Repeat.Times(2);
			Expect.Call(_rule.RuleKey).Return("1").Repeat.Twice();
			Expect.Call(_rule2.RuleKey).Return("2").Repeat.Twice();

			_mocks.ReplayAll();

			setupBrokenRuleList();

			BrokenRule[] forRule2 = _list.GetBrokenRulesForRule(_rule2);

			Assert.AreEqual(1, forRule2.Length);
			Assert.AreEqual(_two, forRule2[0]);
		}

		private void setupBrokenRuleList()
		{
			_one = new BrokenRule("P", null, _rule);
			_two = new BrokenRule("P", null, _rule2);
			_three = new BrokenRule("A", null, _rule);

			_list = new BrokenRuleList();

			_list.Add(_one);
			_list.Add(_two);
			_list.Add(_three);			
		}

		[Test]
		public void Should_Correctly_Return_Yes_If_BrokenRule_With_Given_Error_Exists()
		{
			SetupResult.For(_rule.ErrorFormat).Return("{key} = {value}");
			SetupResult.For(_rule2.ErrorFormat).Return("{key} != {value}");

			_mocks.ReplayAll();

			_one = new BrokenRule("P", "V", _rule);		
			_two = new BrokenRule("P", null, _rule2);

			_list = new BrokenRuleList();

			_list.Add(_one);
			_list.Add(_two);

			Assert.IsTrue(_list.ContainsError("P = V"));
		}

		[Test]
		public void GetAllErrors_Should_Return_All_Errors()
		{
			BrokenRuleList brokenRules = new BrokenRuleList();

			brokenRules.Add(new BrokenRule("one", null, Rule.IsRequired));
			brokenRules.Add(new BrokenRule("two", "ssn", Rule.IsSSN));

			Assert.AreEqual(2, brokenRules.GetAllErrors().Length);
			Assert.AreEqual("one is required.", brokenRules.GetAllErrors()[0]);
			Assert.AreEqual("ssn is not a valid social security number.", brokenRules.GetAllErrors()[1]);
		}
	}
}
